Virtual instruction architectures (such as Java™ bytecodes) are designed for high efficiency of verification, loading, and execution by a family or virtual machine implementations running on a range of platforms. A virtual machine may constitute a software implementation of a machine or computer that executes virtual instructions as if it were a real machine or computer. The platform range for Java™ generally spans everything from multicore servers to low-power portable devices, such as cellular telephones and personal digital assistants, and includes every major non-virtual instruction architecture (such as the x86 instruction architecture utilized in Pentium™ family of microprocessors or the PowerPC instruction architecture utilized in the PowerPC G4™ family of microprocessors).
On many platforms, the virtual instructions may be further processed by compiling them into machine code. Machine code may constitute low-level code executed by the hardware of a machine or computer, such as by a processing unit of the machine or computer. Virtual instruction compilation, like source code compilation, generally involves front end, middle, and back end activities. Front end activities generally operate on bytecodes to generate intermediate representations by performing multiple passes of block structure reconstruction, decoding, preprocessing, structure analysis, and semantic analysis. Middle and/or back end activities generally include multiple passes performed upon the intermediate representation of analysis, optimization, and machine code generation.
Though many virtual machines include interpreters, which can directly execute the virtual instructions with little or no adjustment, extra speed may be obtained from direct hardware execution of native code (i.e., machine code). The virtual instructions may be compiled into machine code at runtime utilizing a just-in-time compiler, wherein the just-in-time compiler performs the middle and back end activities for compiling the virtual instructions into machine code. Less often, the virtual instructions may be compiled into machine code prior to execution by an ahead-of-time compiler that performs the middle and back end activities for compiling the virtual instructions into machine code.
Just-in-time compilation is generally a complex process and may result in delays in the start of program execution, as well as the speed at which the program executes after starting. The execution costs of just-in-time compilation may be hidden by running interpretively during start-up, but running interpretively also may slow execution because the program starts in an interpretive execution mode instead of at the maximum execution speed of native compiled code (i.e., machine code). Just-in-time compilation of existing bytecode designs is inherently a multi-pass process, involving (even in the simplest just-in-time compilers) multiple layers of intermediate representation, and iterative resolutions of complex issues such as type inference, liveness analysis, and register spilling. While continuous improvements over time in processor speed, and memory speed and density tend to decrease processing unit cycle and memory costs, the cost of just-in-time compilation is still significant, particularly as current computing device systems are limited by memory bandwidth and just-in-time compilation phases may require the manipulation of data sets much larger than the eventual machine code. When a program is being executed on a platform with limited resources, the machine cycles and/or other resources required for multiple passes of just-in-time compilation may result in delays in program execution that are unacceptable for users.
Ahead of time compilation may not involve the same execution time delays as just-in-time compilation, as compilation into machine code is performed prior to execution. However, the program may no longer be portable between platforms after ahead of time compilation into machine code. Further, ahead of time compilation may forgo the benefits of compilation at runtime, since some information about the application is available only while the application is running, and that information may be crucial to optimizing its further execution.